概述
ReentrantLock
顾名思义就是可重入锁,即当前持有该锁的线程能够多次获取该锁,无需等待。
ReentrantLock 和 synchronized 的区别
相同点
- 都是可重入锁
不同点
synchronized
是依赖于JVM实现的,而ReenTrantLock
是JDK实现的synchronized
的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock
需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,或者在加锁的代码块内由于程序异常退出而没有释放锁造成死锁,所以最好在finally
中声明释放锁。ReenTrantLock
可以指定是公平锁还是非公平锁。而synchronized
只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。ReenTrantLock
提供了一个Condition
(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized
要么随机唤醒一个线程要么唤醒全部线程。一个Condition
对象的signal
(signalAll
)方法和该对象的await
方法是一一对应的,也就是一个Condition
对象的signal
(signalAll
)方法不能唤醒其他Condition
对象的await
方法。ReenTrantLock
提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()
来实现这个机制。
Condition 和 Object的wait和notify/notifyAll 的区别
类似点
Condition
对象的awiat
方法和Object
对象的wait
方法等效。调用时也必须获得锁。Condition
对象的signal
方法和Object
对象的notify
方法等效。调用时也必须获得锁。Condition
对象的signalAll
方法和Object
对象的notifyAll
方法等效。调用时也必须获得锁。
不同点
- Condition能够支持多个等待队列(new 多个Condition对象),而Object方式只能支持一个
使用方法
ReentrantLock(boolean fair)
可以根据传入的参数来创建两种不同的锁:
- new ReentrantLock(true):公平锁,线程获取锁的顺序是按照加锁顺序来的
- new ReentrantLock(false):非公平锁,抢锁机制,先lock的线程不一定先获得锁。
1 | private ReentrantLock mLock = new ReentrantLock(); |
1 | 17:16:01.072 E/Test: Thread1 start |
配合 Condition 使用:
1 | private ReentrantLock mLock = new ReentrantLock(true); |
1 | 17:27:52.250 E/Test: Thread1 start |
从这里可以看出,只调用 condition1.signalAll()
后,Thread3 后面没有被唤醒。
下面来看一下在 Thread4 中调用 condition2.signalAll()
的执行情况。
1 | Log.e("Test", Thread.currentThread().getName() + " condition1.signalAll()"); |
1 | 17:36:23.026 E/Test: Thread1 start |
Thread3 被唤醒,得到锁后得以继续执行。